<!-- 控件视图-自由容器 -->
<template>
    <div
        ref="widgetDomRef"
        data-name="widget-view-free-vessel"
        :data-id="widgetData.eles.id"
        class="widget-view-free-vessel"
        :class="[...customClass]"
        :style="customStyle"
    >
        <template v-if="preview">
            <template v-for="(item, index) in widgetList" :key="index">
                <div class="widget-view-free-vessel-item">
                    <widget-view
                        :element="item"
                        :free="true"
                        :free-parent="widgetDomRef"
                        :preview="preview"
                    />
                </div>
            </template>
        </template>
        <template v-else>
            <draggable
                :modelValue="widgetList"
                v-bind="{
                    ...draggableConfig,
                    disabled: draggableDisabled || !dragoverStatus
                }"
                class="draggable-content"
                @update:modelValue="onUpdateWidgetList"
                @add="onDragAdd"
                @dragenter.navtive.stop="onDragenter"
                @dragleave.navtive.stop="onDragleave"
                @dragover.navtive.stop="onDragover"
                @drop.navtive.stop="onDrop"
                @mousedown.native="onDragMousedown"
            >
                <template #item="{ element, index }">
                    <div class="widget-view-free-vessel-item">
                        <widget-view
                            :element="element"
                            :free="true"
                            :free-parent="widgetDomRef"
                        />
                    </div>
                </template>
            </draggable>

            <div v-if="widgetList.length === 0 && !draggableDisabled" class="empty-placeholder">
                {{ placeholder }}
            </div>
            <div v-if="draggableDisabled" class="disable-placeholder">
                {{ disabledPlaceholder }}
            </div>

            <div ref="selectRegion" class="select-region"></div>
            <widget-view-free-vessel-checkbox
                :widget-ids="selectBoxWidgetIds"
                :parent-dom="widgetDomRef"
            />
        </template>
        <slot></slot>
    </div>
</template>

<script>
import { defineComponent, toRefs, ref, computed } from 'vue'
import useWidget from '@/libs/edit/widgetData'
import useWidgetDraggable from '@/libs/edit/widgetDraggable'
import useWidgetView from '@/libs/edit/widgetView'
import usePageHistory from '@/libs/edit/pageHistory'
import usePhoneZoom from '@/libs/edit/phoneZoom'
import WidgetViewFreeVesselCheckbox from './widget-view-free-vessel-checkbox.vue'
export default defineComponent({
    name: 'WidgetViewFreeVessel',
    components: {
        WidgetViewFreeVesselCheckbox
    },
    props: {
        // 控件列表
        modelValue: {
            type: Array,
            default: () => ([])
        },
        // 容器控件数据
        widgetData: {
            type: Object,
            default: () => ({})
        },
        // 禁用
        disabled: {
            type: Boolean,
            default: false
        },
        // 自定义style
        customStyle: {
            type: Object,
            default: () => ({})
        },
        // 自定义class
        customClass: {
            type: Array,
            default: () => ([])
        },
        // 占位符
        placeholder: {
            type: String,
            default: '拖拽组件到面板'
        },
        // 禁用时的占位符
        disabledPlaceholder: {
            type: String,
            default: '不可放置'
        },
        // 预览模式
        preview: {
            type: Boolean,
            default: false
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup(props, { emit }) {
        const {
            modelValue,
            widgetData,
            disabled,
            customStyle,
            customClass,
            placeholder,
            disabledPlaceholder,
            preview
        } = toRefs(props)

        const {
            selectWidgetIds,
            onSelectWidget
        } = useWidget()

        const {
            draggableConfig,
            draggableHandleName
        } = useWidgetDraggable()

        const {
            onAddPageHistory
        } = usePageHistory()

        const {
            getWidgetViewDom
        } = useWidgetView()

        const {
            getZoomNum
        } = usePhoneZoom()

        const widgetDomRef = ref(null)
        const draggableDom = ref(null)

        const widgetList = computed(() => modelValue.value)
        const draggableDisabled = computed(() => disabled.value)

        let draggableWidgetList = []
        const onUpdateWidgetList = list => {
            draggableWidgetList = list
        }
        const onDragAdd = e => {
            onAddWidget(draggableWidgetList[e.newIndex])
        }

        const onAddWidget = widget => {
            onAddWidgetAttrs(widget)
            widgetList.value.push(widget)
            onSelectWidget([widget.eles.id])
            onAddPageHistory()
        }
        // 添加控件属性(控件位置大小)
        const onAddWidgetAttrs = widget => {
            const event = window.event
            event.preventDefault()
            event.stopPropagation()

            const { x: eventX = 0, y: eventY = 0 } = event
            const { x: domX = 0, y: domY = 0 } = widgetDomRef.value.getBoundingClientRect()
            const left = getZoomNum(eventX - domX)
            const top = getZoomNum(eventY - domY)

            const widgetStyle = widget.eles.style
            // 添加位置属性
            widgetStyle['position'] = 'absolute'
            widgetStyle['left'] = left + 'px'
            widgetStyle['top'] = top + 'px'

            // 删除 margin 属性
            delete widgetStyle['margin-top']
            delete widgetStyle['margin-left']
            delete widgetStyle['margin-right']
            delete widgetStyle['margin-bottom']

            // 限制宽高，避免超出父容器
            // todo 待精进
            if (widgetStyle.height) {
                const widgetHeight = widgetStyle.height.indexOf('px') !== -1 ? parseInt(widgetStyle.height) : 0
                const offsetHieght = widgetHeight + top - parseInt(widgetData.value.eles.style.height)
                if (offsetHieght > 0) {
                    widgetStyle['height'] = (parseInt(widgetData.value.eles.style.height) - top - 10) + 'px'
                }
            }
            if (widgetStyle.width) {
                const widgetWidth = widgetStyle.width.indexOf('px') !== -1 ? parseInt(widgetStyle.width) : 0
                const offsetWidth = widgetWidth + left - parseInt(widgetData.value.eles.style.width)
                if (offsetWidth > 0) {
                    widgetStyle['width'] = (parseInt(widgetData.value.eles.style.width) - left - 10) + 'px'
                }
            }
        }

        const dragoverStatus = ref(false)
        // 当被鼠标拖动的对象进入其容器范围内时触发此事件
        const onDragenter = e => {
            dragoverStatus.value = true
        }
        // 当被鼠标拖动的对象离开其容器范围内时触发此事件
        const onDragleave = e => {
            dragoverStatus.value = false
        }
        // 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
        const onDragover = e => {
            dragoverStatus.value = true
        }
        // 在一个拖动过程中，释放鼠标键时触发此事件
        const onDrop = e => {
            dragoverStatus.value = false
        }

        // 选中框中控件id集合
        const selectBoxWidgetIds = computed(() => {
            return selectWidgetIds.value.filter(id => widgetList.value.some(item => item.eles.id === id))
        })

        const selectRegion = ref(null)
        const onDragMousedown = e => {
            e = e || window.event

            // shift + 鼠标左键，拖动可创建选择区域
            if (!e.shiftKey) return
            e.stopPropagation()
            e.preventDefault()

            // 鼠标按下时坐标
            const { clientX: mouseX, clientY: mouseY } = e

            // 选择区域的宽高和坐标
            const domL = parseInt(e.offsetX)
            const domT = parseInt(e.offsetY)
            const domW = 0
            const domH = 0

            // 更新后dom的宽高和坐标
            let newDomL = domL
            let newDomT = domT
            let newDomW = domW
            let newDomH = domH
            let frame = null

            let selectIds = []
            const widgetDoms = {}
            widgetList.value.forEach(item => {
                const id = item.eles.id
                const { offsetTop, offsetLeft, offsetWidth, offsetHeight } = getWidgetViewDom(id)
                widgetDoms[id] = {
                    top: offsetTop,
                    bottom: offsetTop + offsetHeight,
                    left: offsetLeft,
                    right: offsetLeft + offsetWidth
                }
            })
            // 窗口鼠标移动事件
            document.onmousemove = event => {
                const offsetX = getZoomNum(event.clientX - mouseX)
                const offsetY = getZoomNum(event.clientY - mouseY)
                newDomL = (offsetX >= 0) ? domL : (offsetX + domL)
                newDomT = (offsetY >= 0) ? domT : (offsetY + domT)
                newDomW = (offsetX >= 0) ? (offsetX + domW) : (-offsetX + domW)
                newDomH = (offsetY >= 0) ? (offsetY + domH) : (-offsetY + domH)
                // 更新视图
                frame = requestAnimationFrame(() => {
                    selectRegion.value.style.cssText += `display:block;left:${newDomL}px;top:${newDomT}px;width:${newDomW}px;height:${newDomH}px;`
                })
                // 当前选择区域内控件id集合
                selectIds = Object.keys(widgetDoms).filter(key => {
                    const { top, bottom, left, right } = widgetDoms[key]
                    return (left >= newDomL) && (right <= newDomL + newDomW) && (top >= newDomT) && (bottom <= newDomT + newDomH)
                })
                // 比较当前选择区域控件id集合与之前选中控件id集合，避免频繁调用 onSelectWidget
                if (selectIds.length !== selectWidgetIds.value.length) {
                    onSelectWidget(selectIds)
                }
            }

            document.onmouseup = () => {
                selectRegion.value.style.cssText += 'display:none;'
                cancelAnimationFrame(frame)
                document.onmousemove = null
                document.onmouseup = null
            }
        }

        return {
            widgetDomRef,
            draggableDom,
            draggableConfig,
            draggableHandleName,
            placeholder,
            disabledPlaceholder,
            preview,

            customStyle,
            customClass,
            widgetList,
            draggableDisabled,

            onUpdateWidgetList,
            onDragAdd,

            dragoverStatus,
            onDragenter,
            onDragleave,
            onDragover,
            onDrop,

            selectBoxWidgetIds,
            
            selectRegion,
            onDragMousedown
        }
    }
})
</script>

<style lang="less" scoped>
@import './widget-view-free-vessel.less';
</style>